<?php
/**
 * Copyright (c) 2018-2019.
 *  This file is part of the moonpie production
 *  (c) johnzhang <875010341@qq.com>
 *  This source file is subject to the MIT license that is bundled
 *  with this source code in the file LICENSE.
 */

namespace moonpie\plugin\wechat_account\service;


use EasyWeChat\Kernel\Support\Arr;
use moonpie\plugin\wechat_account\model\WechatAccount;
use moonpie\plugin\wechat_account\validate\CachingTypeValidator;
use moonpie\plugin\wechat_account\validate\LoggingTypeValidator;
use Symfony\Component\Cache\Simple\RedisCache;
use think\Cache;
use think\Validate;

class WechatAccountServiceConfig
{
    const SCOPE_CACHING = 'caching';
    const SCOPE_LOGGING = 'logging';
    private $account;
    private $error;
    private $configData;
    protected $validators = [];
    public function __construct(WechatAccount $account)
    {
        $this->account = $account;
        $this->validators[static::SCOPE_CACHING] = new CachingTypeValidator();
        $this->validators[static::SCOPE_LOGGING] = new LoggingTypeValidator();
    }

    public function saveConfig($scope, array $config = [])
    {
        $validator = $this->getValidator($scope);
        $result = $validator->check($config);
        if(!$result) {
            $this->error = $validator->getError();
            return false;
        }
        $data = $this->getConfigData();
        $data[$scope] = $config;
        $this->saveConfigData($data);
        return $data;
    }
    public function getCachingService()
    {
        $type = $this->getScopeConfig(static::SCOPE_CACHING, 'cacheType');
        switch ($type) {
            case 'redis':
                if(extension_loaded('redis')){
                    $redis = new \Redis();
                    $host = $this->getScopeConfig(static::SCOPE_CACHING, 'cacheData.host', '127.0.0.1');
                    $port = $this->getScopeConfig(static::SCOPE_CACHING, 'cacheData.port', 6379);
                    $db_select = $this->getScopeConfig(static::SCOPE_CACHING, 'cacheData.db_select', 0);
                    $redis->connect($host, $port, 5);
                    $password = $this->getScopeConfig(static::SCOPE_CACHING, 'cacheData.password' );
                    //var_dump($host, $port, $db_select, $password);exit;
                    if(!empty($password)) {
                        $result = $redis->auth($password);
                        if(!$result) return null;
                        $result = $redis->select($db_select);
                        if(!$result) return null;
                    }
                    return new RedisCache($redis);
                }else if(class_exists('\Predis\Client')) {
                    $host = $this->getScopeConfig(static::SCOPE_CACHING, 'cacheData.host', '127.0.0.1');
                    $port = $this->getScopeConfig(static::SCOPE_CACHING, 'cacheData.port', 6379);
                    $password = $this->getScopeConfig(static::SCOPE_CACHING, 'cacheData.port', 6379);
                    $db_select = $this->getScopeConfig(static::SCOPE_CACHING, 'cacheData.db_select', 0);
                    $parameters = [
                        'schema' => 'tcp', 'host' => $host, 'port' => $port,
                    ];
                    $options = [
                        'parameters' => [
                            'database' => $db_select,
                        ]
                    ];
                    if(!empty($password)) $options['parameters']['password'] = $password;
                    $client = new \Predis\Client($parameters, $options);
                    return new RedisCache($client);
                }
                break;
        }
        return null;
    }
    public function getLoggingConfig()
    {
        $logs = [
            'default' => '_inner',
            'channels' => [
                '_inner' => [
                    'driver' => $this->getScopeConfig(static::SCOPE_LOGGING, 'loggingType'),
                    'level' => $this->getScopeConfig(static::SCOPE_LOGGING, 'loggingData.level'),
                    'path' => $this->resolveLogPath($this->getScopeConfig(static::SCOPE_LOGGING, 'loggingData.path')),
                    'days' => $this->getScopeConfig(static::SCOPE_LOGGING, 'loggingData.days'),
                ]
            ],
        ];
        return $logs;
    }
    protected function resolveLogPath($path)
    {
        return is_absolute_path($path) ? $path : LOG_PATH . ltrim($path, '\\/');
    }
    public function getValidator($scope)
    {
        if(isset($this->validators[$scope]) && $this->validators[$scope] instanceof Validate) {
            return $this->validators[$scope];
        }
        throw new \LogicException(sprintf('invalid validator for scope: %s', $scope));
    }
    public function getError()
    {
        return $this->error;
    }
    public function getConfigData()
    {
        if(is_null($this->configData)){
            $this->configData = Cache::get($this->getCacheKey(), [
                static::SCOPE_CACHING => [
                    'cacheType' => 'default',
                    'cacheData' => [],
                ],
                static::SCOPE_LOGGING => [
                    'loggingType' => 'daily',
                    'loggingData' => [
                        'days' => 7,
                        'path' => 'mp-wechat-account-' . $this->account->getId() . '.log',
                    ]
                ],
            ]);
        }
        return $this->configData;
    }
    protected function saveConfigData($data)
    {
        Cache::set($this->getCacheKey(), $data);
        $this->configData = $data;
        return true;
    }
    protected function getCacheKey()
    {
        return sprintf('system:wechat-account:%s:service-config', $this->account->getAppId());
    }
    public function getScopeConfig($scope, $field, $default = null) {
        return Arr::get($this->getConfigData(), "{$scope}.{$field}", $default);
    }
}